package test.stationLogic;

import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import junit.framework.TestCase;

import uicgas.globaldata.*;
import uicgas.station.*;

public class CommandLogicTestCases extends TestCase
{

	StationLogic station;

	// arrays to keep track of each pump and register
	private ArrayList<Pump> pump_list;
	private ArrayList<Register> register_list;
	private int pumpCount;
	private int registerCount;

	// queues to manage decommissioned pumps
	// and pumps at which assistance from
	// an operator is needed
	//private DecommissionedPumps decomm_pumps;
	//private AssistanceQueue assistance_needed;
	private ConcurrentLinkedQueue<Pump> decomm_pumps;
	private ConcurrentLinkedQueue<Pump> assistance_needed;

	// objects to communicate with
	// pumps and registers through Socket
	private Server_Comm pumpServer;
	private Server_Comm registerServer;
	private boolean pumpServerStarted;
	private boolean registerServerStarted;

	// password for recommissioning a pump
	private String recomm_password;
	private boolean recomm_authorized;

	//Fields for ServerComm
	int listenPort;
	private ClientTypes serverType;

	public CommandLogicTestCases()
	{

	}

	////////////
	//Test Cases
	//All command test cases assume that the servers aren't started
	////////////

	public int testConnectPump()
	{
		//test pump count and pump list
		int result = 0;
		station = new StationLogic(50020, 50021, "password");

		//CASE data==null
		station.connectPump(null);
		getStationLogicClassFields(station);
		if (pumpCount != 0)
		{
			System.out.println("1. Failed to catch null payload");
			result = -1;
		}

		//CASE data of type Password
		//to catch ClassCastException at runtime
		station.connectPump(new Password());
		getStationLogicClassFields(station);
		if (pumpCount != 0)
		{
			System.out.println("2. Failed to catch wrong payload type");
			result = -1;
		}

		//CASE count = 0
		station = new StationLogic(50020, 50021, "password");
		station.connectPump(new SelfAnnouncement(0, -1));
		getStationLogicClassFields(station);
		if (pumpCount != 1)
		{
			System.out.println("3. Failed to add Pump ID: 0");
			result = -1;
		}
		if (pump_list.size() != 1
				&& pump_list
						.indexOf(new Pump(0, null, 0.0, States.DEACTIVATED)) != -1)
		{
			System.out
					.println("4. Failed to add Pump ID: 0 to arraylist. ArrayList size incorrect...");
			result = -1;
		}

		//CASE count = 1
		station.connectPump(new SelfAnnouncement(1, -1));
		getStationLogicClassFields(station);
		if (pumpCount != 2)
		{
			System.out.println("5. Failed to add Pump ID: 1");
			result = -1;
		}
		if (pump_list.size() != 2
				&& pump_list
						.indexOf(new Pump(1, null, 0.0, States.DEACTIVATED)) != -1)
		{
			System.out
					.println("6. Failed to add Pump ID: 1 to arraylist. ArrayList size incorrect...");
			result = -1;
		}
		//CASE count = 20
		for (int i = 2; i < 20; i++)
		{
			station.connectPump(new SelfAnnouncement(i, -1));
		}
		station.connectPump(new SelfAnnouncement(20, -1));
		getStationLogicClassFields(station);
		if (pumpCount != 20)
		{
			System.out
					.println("7. Incorrect pumpCount after attempting to add pump to full list...");
			result = -1;
		}
		if (pump_list.size() != 20)
		{
			System.out
					.println("8. ArrayList size incorrect after attempting to add pump to full list...");
			result = -1;
		}

		//CASE pump ID already exists in list
		station = new StationLogic(50020, 50021, "password");
		station.connectPump(new SelfAnnouncement(0, -1));
		station.connectPump(new SelfAnnouncement(0, -1));
		getStationLogicClassFields(station);
		if (pumpCount != 1)
		{
			System.out
					.println("9. Incorrect pumpCount after attempting to add pump that already exists...");
			result = -1;
		}
		if (pump_list.size() != 1)
		{
			System.out
					.println("10. ArrayList size incorrect after attempting to add pump that already exists...");
			result = -1;
		}
		return result;
	}

	public int testConnectRegister()
	{
		int result = 0;

		station = new StationLogic(50020, 50021, "password");

		//CASE data==null
		station.connectRegister(null);
		getStationLogicClassFields(station);
		if (registerCount != 0)
		{
			System.out.println("11. Failed to catch null payload");
			result = -1;
		}

		//CASE data of type Password
		station.connectRegister(new Password());
		getStationLogicClassFields(station);
		if (registerCount != 0)
		{
			System.out.println("12. Failed to catch wrong payload type");
			result = -1;
		}

		//CASE count = 0
		station = new StationLogic(50020, 50021, "password");
		station.connectRegister(new SelfAnnouncement(0, -1));
		getStationLogicClassFields(station);
		if (registerCount != 1)
		{
			System.out.println("13. Failed to add Register ID: 0");
			result = -1;
		}
		if (register_list.size() != 1
				&& register_list.indexOf(new Register(0)) != -1)
		{
			System.out
					.println("14. Failed to add Register ID: 0 to arraylist. ArrayList size incorrect...");
			result = -1;
		}

		//CASE count = 1
		station.connectRegister(new SelfAnnouncement(1, -1));
		getStationLogicClassFields(station);
		if (registerCount != 2)
		{
			System.out.println("15. Failed to add Register ID: 1");
			result = -1;
		}
		if (register_list.size() != 2
				&& register_list.indexOf(new Register(1)) != -1)
		{
			System.out
					.println("16. Failed to add Register ID: 1 to arraylist. ArrayList size incorrect...");
			result = -1;
		}
		//CASE count = 20
		for (int i = 2; i < 20; i++)
		{
			station.connectRegister(new SelfAnnouncement(i, -1));
		}
		station.connectRegister(new SelfAnnouncement(20, -1));
		getStationLogicClassFields(station);
		if (registerCount != 20)
		{
			System.out
					.println("17. Incorrect registerCount after attempting to add register to full list...");
			result = -1;
		}
		if (register_list.size() != 20)
		{
			System.out
					.println("18. ArrayList size incorrect after attempting to add register to full list...");
			result = -1;
		}

		//CASE Register ID already exists in list
		station = new StationLogic(50020, 50021, "password");
		station.connectRegister(new SelfAnnouncement(0, -1));
		station.connectRegister(new SelfAnnouncement(0, -1));
		getStationLogicClassFields(station);
		if (registerCount != 1)
		{
			System.out
					.println("19. Incorrect registerCount after attempting to add Register that already exists...");
			result = -1;
		}
		if (register_list.size() != 1)
		{
			System.out
					.println("20. ArrayList size incorrect after attempting to add Register that already exists...");
			result = -1;
		}

		return result;
	}

	public int testChangePumpState()
	{
		int result = 0;

		station = new StationLogic(50020, 50021, "password");

		//must add a pump here...
		station.connectPump(new SelfAnnouncement(0, -1));

		//CASE data==null
		station.changePumpState(null);
		getStationLogicClassFields(station);
		if (pump_list.get(pump_list.indexOf(new Pump())).getState() != States.DEACTIVATED)
		{
			System.out
					.println("21. Failed to catch null payload in changePumpState()");
			result = -1;
		}

		//CASE data of type Password
		station.changePumpState(new Password());
		getStationLogicClassFields(station);
		if (pump_list.get(pump_list.indexOf(new Pump())).getState() != States.DEACTIVATED)
		{
			System.out
					.println("22. Failed to catch wrong payload type in changePumpState()");
			result = -1;
		}

		//CASE pumpIndex < 0
		station.changePumpState(new PumpState(States.DEACTIVATED,
				States.ACTIVATED, 1));
		getStationLogicClassFields(station);
		if (pump_list.get(pump_list.indexOf(new Pump())).getState() == States.ACTIVATED)
		{
			System.out
					.println("23. Failed to catch non existant pump in changePumpState()");
			result = -1;
		}

		//CASE pumpIndex > 0
		station.changePumpState(new PumpState(States.DEACTIVATED,
				States.ACTIVATED, 0));
		getStationLogicClassFields(station);
		if (pump_list.get(pump_list.indexOf(new Pump())).getState() == States.DEACTIVATED)
		{
			System.out
					.println("24. Failed to find pump in arraylist in changePumpState()");
			result = -1;
		}

		//CASE currentPump.getState() == stateChange.getCurrentState()
		station.changePumpState(new PumpState(States.ACTIVATED,
				States.DEACTIVATED, 0));
		getStationLogicClassFields(station);
		if (pump_list.get(pump_list.indexOf(new Pump())).getState() == States.ACTIVATED)
		{
			System.out
					.println("25. Failed to recognize identical current states of pump and pump in arraylist in changePumpState()");
			result = -1;
		}

		//CASE currentPump.getState() != stateChange.getCurrentState()
		station = new StationLogic(50020, 50021, "password");
		station.connectPump(new SelfAnnouncement(0, -1));
		station.changePumpState(new PumpState(States.ACTIVATED,
				States.DECOMMISSIONED, 0));
		getStationLogicClassFields(station);
		if (pump_list.get(pump_list.indexOf(new Pump())).getState() == States.DECOMMISSIONED)
		{
			System.out
					.println("26. Failed to catch invalid current state of pumpState in changePumpState()");
			result = -1;
		}

		//CASE currentPump.getState() != stateChange.getNewState()
		//identical to case 25

		//CASE currentPump.getState() == stateChange.getNewState()
		station = new StationLogic(50020, 50021, "password");
		station.connectPump(new SelfAnnouncement(0, -1));
		station.changePumpState(new PumpState(States.DEACTIVATED,
				States.DEACTIVATED, 0));
		getStationLogicClassFields(station);
		if (pump_list.get(pump_list.indexOf(new Pump())).getState() != States.DEACTIVATED)
		{
			System.out
					.println("27. Failed to catch identical new state of pumpState in changePumpState()");
			result = -1;
		}

		//CASE registerServer.sendMessage(toRegister, -1)!=0
		//Identical to case 24

		//CASE registerServer.sendMessage(toRegister, -1)==0
		//server must be started
		station.startRegisterServer();
		station.changePumpState(new PumpState(States.DEACTIVATED,
				States.ACTIVATED, 0));

		return result;
	}

	//the results of this test are indeterminate
	public int testAnnounceDecommPumps()
	{
		int result = 0;
		
		//CASE data == null
		station = new StationLogic(50020, 50021, "password");
		station.connectPump(new SelfAnnouncement(0, -1));
		getStationLogicClassFields(station);
		decomm_pumps.add(new Pump());
		station.announceDecommPumps(null);
		
		//CASE data object of type Password
		station.announceDecommPumps(new Password());
		
		//CASE SelfAnnouncement with valid ID
		station = new StationLogic(50020, 50021, "password");
		station.connectRegister(new SelfAnnouncement(0, -1));
		station.announceDecommPumps(new SelfAnnouncement(1,-1));
		//will print error message
		
		//CASE SelfAnnouncement with invalid ID
		station = new StationLogic(50020, 50021, "password");
		station.announceDecommPumps(new SelfAnnouncement(1,-1));
		//will print error message
		
		//Cannot test these since no registers are connected
		//CASE registerServer.sendMessage(toRegister, -1) != 0
		//CASE registerServer.sendMessage(toRegister, -1) == 0
		
		return result;
	}
	
	public int testAnnounceAllConnectedPumps()
	{
		int result=0;
		station = new StationLogic(50020, 50021, "password");
		station.connectPump(new SelfAnnouncement(0, -1));
		getStationLogicClassFields(station);
		
		//CASE data == null
		station.announceAllConnectedPumps(null);
		
		//CASE data object of type Password
		station.announceAllConnectedPumps(new Password());
		
		//CASE SelfAnnouncement with valid ID
		station.connectRegister(new SelfAnnouncement(0,-1));
		station.announceAllConnectedPumps(new SelfAnnouncement(0,-1));
		//CASE SelfAnnouncement with innvalid ID
		station.announceAllConnectedPumps(new SelfAnnouncement(1,-1));
		//CASE registerServer.sendMessage(toRegister, -1) != 0
		//CASE registerServer.sendMessage(toRegister, -1) == 0
		
		return result;
	}
	
	public int testAnnouncePumpState()
	{
		int result=0;
		station = new StationLogic(50020, 50021, "password");
		station.connectPump(new SelfAnnouncement(0, -1));
		getStationLogicClassFields(station);
		station.connectPump(new Pump());
		station.connectRegister(new Register());
		
		//CASE data == null
		station.announcePumpState(null);
		
		//CASE data object of type Password
		station.announcePumpState(new Password());
		
		//CASE SelfAnnouncement with valid ID
		station.announcePumpState(new SelfAnnouncement(0,0));
		
		//CASE SelfAnnouncement with invalid ID
		station.announcePumpState(new SelfAnnouncement(1,0));
		
		//CASE SelfAnnouncement with valid reqID
		station.announcePumpState(new SelfAnnouncement(0,0));
		
		//CASE SelfAnnouncement with invalid reqID
		station.announcePumpState(new SelfAnnouncement(0,1));
		
		//CASE case where both ID and reqID are both valid
		//same as above
		
		//CASE case where both ID and reqID are both invalid
		station.announcePumpState(new SelfAnnouncement(1,1));
		
		//CASE registerServer.sendMessage(toRegister, regID) != 0
		//CASE registerServer.sendMessage(toRegister, regID) == 0
		//only the case where sendMessage returns -1 is possible here
		
		return result;
	}
	
	public int testNotifyRegisterAssistanceNeeded()
	{
		//I actually get to check fields in this test!
		int result=0;
		station = new StationLogic(50020, 50021, "password");
		station.connectPump(new SelfAnnouncement(0, -1));
		getStationLogicClassFields(station);
		station.connectPump(new Pump());
		station.connectRegister(new Register());
		
		//CASE data == null
		station.notifyRegisterAssistanceNeeded(null);
		getStationLogicClassFields(station);
		//check that pump is still in arraylist
		//and not in decomm queue
		if(pump_list.indexOf(new Pump())==-1 || decomm_pumps.contains(new Pump()))
			System.out.println("28. Failed to catch null data in NotifyRegisterAssistanceNeeded()...");
		
		//CASE data object of type Password
		station.notifyRegisterAssistanceNeeded(new Password());
		getStationLogicClassFields(station);
		if(pump_list.indexOf(new Pump())==-1 || decomm_pumps.contains(new Pump()))
			System.out.println("29. Failed to catch incorrect data type in NotifyRegisterAssistanceNeeded()...");
		
		//CASE pumpID valid
		station.notifyRegisterAssistanceNeeded(new SelfAnnouncement(0, -1));
		getStationLogicClassFields(station);
		if(pump_list.indexOf(new Pump())>-1 || !decomm_pumps.contains(new Pump()))
			System.out.println("30. Failed to move pump no. 0 from arraylist to decomm queue in NotifyRegisterAssistanceNeeded()...");
		
		//CASE pumpID invalid
		station.notifyRegisterAssistanceNeeded(new SelfAnnouncement(321, -1));
		getStationLogicClassFields(station);
		if(pump_list.indexOf(new Pump())==-1 || decomm_pumps.contains(new Pump()))
			System.out.println("31. Failed to catch invalid pumpID in NotifyRegisterAssistanceNeeded()...");
		
		//CASE registerServer.sendMessage(toRegister, -1) == 0
		//CASE registerServer.sendMessage(toRegister, -1) != 0
		
		return result;
	}
	
	public int testChargeCreditCard()
	{
		int result=0;
		station = new StationLogic(50020, 50021, "password");
		station.connectPump(new SelfAnnouncement(0, -1));
		getStationLogicClassFields(station);
		station.connectPump(new Pump());
		station.connectRegister(new Register());
		
		//CASE data==null
		station.chargeCreditCard(null);
		
		//CASE data object of type Password
		station.chargeCreditCard(new Password());
		
		return result;
	}
	
	public int testValidateCard()
	{
		int result=0;
		station = new StationLogic(50020, 50021, "password");
		station.connectPump(new SelfAnnouncement(0, -1));
		getStationLogicClassFields(station);
		station.connectPump(new Pump(123, null, 0.0, States.DEACTIVATED));
		station.connectRegister(new Register(456));
		
		int pumpSource=123;
		int registerSource=456;
		ClientTypes pumpType=ClientTypes.PUMP;
		ClientTypes registerType=ClientTypes.REGISTER;
		
		//CASE data == null
		station.validateCard(null, pumpSource, pumpType);
		
		//CASE data == Password()
		station.validateCard(new Password(), pumpSource, pumpType);
		
		//CASE sourceType == ClientTypes.PUMP
		station.validateCard(new CreditCard(), pumpSource, pumpType);
		
		//CASE sourceType == ClientTypes.REGISTER
		//CASE sourceID valid
		//CASE sourceID invalid
		
		//CASE pumpID valid, but sourceType == ClientTypes.REGISTER
		//CASE registerID valid, but sourceType == ClientTypes.PUMP
		
		return result;
	}

	//Helper methods
	public void getStationLogicClassFields(StationLogic test)
	{
		// arrays to keep track of each pump and register
		pump_list = test.getPumpList();
		register_list = test.getRegisterList();
		pumpCount = test.getPCount();
		registerCount = test.getRCount();

		// queues to manage decommissioned pumps
		// and pumps at which assistance from
		// an operator is needed
		// DecommissionedPumps decomm_pumps;
		// AssistanceQueue assistance_needed;
		decomm_pumps = test.getDecomList();
		assistance_needed = test.getAssistanceList();

		// objects to communicate with
		// pumps and registers through Socket
		pumpServer = test.getPServer();
		registerServer = test.getRServer();
		pumpServerStarted = test.getPServerStarted();
		registerServerStarted = test.getRServerStarted();

		// password for recommissioning a pump
		recomm_password = test.getRecommPassword();
		recomm_authorized = test.getRecommAuthorization();
	}

	public void getServerCommFields(Server_Comm comm)
	{
		listenPort = comm.getListenPort();
		//		clientSockets = comm.getIntSockMap();
		//		socketClients = comm.getSockIntMap();
		serverType = comm.getServerType();
	}
}
